// jsx -> babel|swc -> React.createElement

const React = {
    createElement(type, props, ...children){
         return{
            type,
            props:{
                ...props,
                children: children.map(child=>{
                    if (typeof child === 'object'){
                        return child
                    }else{
                        return React.createTextElement(child)
                    }
                })
            }
            
         }
    },
    createTextElement(text){
        return{
            type: 'TEXT_ELEMENT',
            props:{
                nodeValue: text,
                children: []
            }
        }
    },

}


// const text = document.createTextNode('')
// text.nodeValue = "小满zs"

const vdom = React.createElement('div', {id: 1}, React.createElement('span', null, '小满zs'))
console.log(vdom, 1111)

// 虚拟dom转fiber结构和时间切片
let nextUnitOfWork = null // 下一个工作单元
let wipRoot = null // 当前正在工作的fiber树
let currentRoot = null // 旧的fiber树
let deletions = null // 存储需要删除的fiber节点 deletions[D] {A,B,C,D} {A,B,C}


function render(element, container){
    // 初始化fiber结构
    wipRoot = {
        dom: container,
        props: {
            children: [element]
        },
        alternate: currentRoot // 旧的fiber树
    }
    deletions = []
    nextUnitOfWork = wipRoot
}

function createDom(fiber){ 
    const dom = fiber.type === 'TEXT_ELEMENT' ? document.createTextNode('') : document.createElement(fiber.type)
    updateDom(dom, {}, fiber.props) // 挂在新属性
    return dom
}

// 更新节点的属性
function updateDom(dom, prevProps, nextProps){
    // 旧的属性删除
    Object.keys(prevProps).filter(name => name !== 'children').forEach(name => {
        dom[name] = ''
    })
    // 新的属性添加
    Object.keys(nextProps).filter(name => name !== 'children').forEach(name => {
        dom[name] = nextProps[name]
    })
}


function workLoop(deadline){ 
    let shouldYield = false
    while (nextUnitOfWork && !shouldYield) { 
        nextUnitOfWork = performUnitOfWork(nextUnitOfWork)
        shouldYield = deadline.timeRemaining() < 1
    }
    // nextUnitOfWork == null 所有的任务都执行完成了 并且还有待提交的工作根
    if (!nextUnitOfWork && wipRoot){
        commitRoot()
    }
    requestIdleCallback(workLoop)
}

requestIdleCallback(workLoop)

function performUnitOfWork(fiber){
    if(!fiber.dom){
        fiber.dom = createDom(fiber)
    }

    //确保每个 Fiber 节点都在内存中有一个对应的 DOM 节点准备好，以便后续在提交阶段更新到实际的 DOM 树中

    // 创建子节点的 Fiber
    // const vdom = React.createElement('div', { id: 1 }, React.createElement('span', null, '小满zs'));
    // 子节点在children中
    const elements = fiber.props.children;
    reconcileChildren(fiber, elements);

    if (fiber.child){
        return fiber.child
    }
    let nextFiber = fiber
    while(nextFiber){
        if (nextFiber.sibling){
            // 返回兄弟
            return nextFiber.sibling
        }
        // 如果没有兄弟，返回父亲 向上查找
        nextFiber = nextFiber.parent
    }
    return null
}

function createFiber(element, parent) {
    return {
        type: element.type,
        props: element.props,
        dom: null,
        parent: parent,
        child: null,
        sibling: null,
        alternate: null,
        effectTag: null
    }
}

function reconcileChildren(fiber, elements){
        // 1.diff 算法
        // 2.形成fiber树
        let index = 0
        let preSibling = null
        let oldFiber = fiber.alternate && fiber.alternate.child // 旧的fiber树
        while (index < elements.length || oldFiber != null) { 
            const element = elements[index]
            // diff 算法
            // 1.复用
            let newFiber = null
            const sameType = oldFiber && element && element.type === oldFiber.type
            if (sameType) { 
                console.log('复用', element)
                newFiber = {
                    type: oldFiber.type,
                    props: element.props,
                    dom: oldFiber.dom,
                    parent: fiber,
                    alternate: oldFiber,
                    effectTag: 'UPDATE' // 更新
                }
            }
            // 2.新增
            if (!sameType && element) { 
                console.log('新增', element)
                newFiber = createFiber(element, fiber)
                newFiber.effectTag = "PLACEMENT" // 新增
            }

            // 3.删除
            if (oldFiber && !sameType) { 
                console.log('删除', element)
                oldFiber.effectTag = "DELETION"
                deletions.push(oldFiber)
            }

            if (index === 0) {
                fiber.child = newFiber
            } else {
                preSibling.sibling = newFiber
            }
            preSibling = newFiber
            index++
        }
    }

    function commitRoot(){
        deletions.forEach(commitWork)
        commitWork(wipRoot.child)
        currentRoot = wipRoot // 存储旧的fiber
        wipRoot = null // 因为把所有的变化都操作完成了回归原始
    }

    function commitWork(fiber){ 
        if (!fiber) { 
            return
        }
        const domParent = fiber.parent.dom
        if (fiber.effectTag === 'PLACEMENT' && fiber.dom != null) { 
            domParent.appendChild(fiber.dom)
        } else if (fiber.effectTag === 'UPDATE' && fiber.dom != null) { 
            updateDom(fiber.dom, fiber.alternate.props, fiber.props)
        } else if (fiber.effectTag === 'DELETION') { 
            domParent.removeChild(fiber.dom)
        }

        commitWork(fiber.child)
        commitWork(fiber.sibling)

    }

    // render(vdom, document.getElementById('root'))
    render(React.createElement('div', {id: "a"}, React.createElement('span', null, '小满zs')), document.getElementById('root'))

    setTimeout(() => { 
        render(React.createElement('div', {id: "a"}, React.createElement('p', null, '新元素')), document.getElementById('root'))
    }, 2000)

    